//
//  YDCanCycleScrollView.swift
//  YDCycleScrollView
//
//  Created by alyadan on 2017/3/15.
//  Copyright © 2017年 alyadan. All rights reserved.
//


import RxSwift
import YD_Util
import MVVM_BaseViewController
import SnapKit

public class YDCanCycleScrollView: YDCycleScrollView {
    
    lazy var leftView: UIView = {
        let x = UIView()
        //        x.backgroundColor = UIColor.red
        return x
    }()
    
    lazy var centerView: UIView = {
        let x = UIView()
        //        x.backgroundColor = UIColor.blue
        return x
    }()
    
    lazy var rightView: UIView = {
        let x = UIView()
        //        x.backgroundColor = UIColor.black
        return x
    }()
    
    
    public override var currentModel: YDCanCycleScrollViewModel {
        return viewModel.value as! YDCanCycleScrollViewModel
    }
    
    lazy var views: [UIView] = [self.leftView, self.centerView, self.rightView]
    
    enum CycleScrollState {
        case leftBoundary
        case left
        case center
        case right
        case rightBoundary
    }
    
    var cycleScrollState = CycleScrollState.center {
        
        didSet {
            if oldValue == self.cycleScrollState {
                
                if oldValue == .center {
                    reAddContentView()
                }
                return
            }
            
            dealCyclePageIndex(state: self.cycleScrollState)
        }
    }
    
    //    var lastState = CycleScrollState.center
    
    func copyView(view: UIView) -> UIView {
        let data = NSKeyedArchiver.archivedData(withRootObject: view)
        return NSKeyedUnarchiver.unarchiveObject(with: data) as! UIView
    }
    
    override public func scrollSetupUI() {
        let _ = views.map { (x: UIView) in
            self.scrollView.addSubview(x)
        }
        
        self.scrollView.showsHorizontalScrollIndicator = false
        
        //        ///即将弃用
        //        if currentModel.yd_contentViews.count == 2 {
        //            currentModel.yd_contentViews
        //                .append(copyView(view: currentModel.yd_contentViews[0]))
        //        }
    }
    
    override func scrollLayoutSubViews() {
        
        for (index, aView) in views.enumerated() {
            aView.frame = CGRect(x: CGFloat(index) * self.frame.width, y: 0, width: self.frame.width, height: self.frame.height)
        }
        
        self.scrollView.contentSize = CGSize(width: CGFloat(views.count) * self.frame.width, height: self.frame.height)
        
        
        if !initFlag {
            self.scrollView.setContentOffset(CGPoint.init(x: CGFloat(currentModel.pageIndex.value) * self.frame.width, y: 0), animated: false)
            initFlag = true
        }
    }
    
    
    
    public override func scrollViewDidScroll(_ scrollView: UIScrollView) {
        
        guard self.frame.width != 0 else{
            return
        }
        
        let pageIndex = Int(scrollView.contentOffset.x / self.frame.width)
        
        if pageIndex != currentModel.pageIndex.value {
            currentModel.pageIndex.value = pageIndex
        }
        
        switch scrollView.contentOffset.x {
        case let x where x == 0:
            cycleScrollState = .leftBoundary
        case let x where x < self.frame.width:
            cycleScrollState = .left
        case let x where x == self.frame.width:
            cycleScrollState = .center
        case let x where x > self.frame.width && x < 2 * self.frame.width:
            cycleScrollState = .right
        case let x where x == self.frame.width * 2:
            cycleScrollState = .rightBoundary
        default:
            return
        }
    }
    
    public override func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        guard self.frame.width != 0 else{
            return
        }
        
        currentModel.pageControlIndex.value = currentModel.cyclePageIndex.value
        
    }
    
    //    public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
    //        print("333-----\(scrollView.contentOffset.x)")
    //    }
    //
    //
    //    public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
    //        print("444-----\(scrollView.contentOffset.x)")
    //    }
    
    public override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        
        guard self.frame.width != 0 else{
            return
        }
        
        currentModel.pageControlIndex.value = currentModel.cyclePageIndex.value
    }
    
    
    public override func bindModelData() {
        
        currentModel.pageControlIndex.asDriver()
            .drive(self.pageControll.rx.currentPage)
            .addDisposableTo(disposeBag)
        
        if currentModel.timerInterval != 0 {
            Observable<Int>.interval(currentModel.timerInterval, scheduler: MainScheduler.instance)
                .asDriver(onErrorJustReturn: 0)
                .drive(onNext: {[unowned self] _ in
                    if self.currentModel.viewCount <= 1 {
                        return
                    }
                    
                    self.scrollView.setContentOffset(CGPoint.init(x: self.frame.width * 2, y: 0), animated: true)
                })
                .addDisposableTo(disposeBag)
            
        }
        
        
        viewModel.asObservable()
            .map{$0 as? YDCanCycleScrollViewModel}
            .filter{$0 != nil}
            .map{$0!}
            .subscribe(onNext: {[unowned self] (x: YDCanCycleScrollViewModel) in
                x.refreshBlock =  {
                    self.reAddContentView()
                }
                self.reAddContentView()
            })
            .addDisposableTo(disposeBag)
    }
    
    //MARK: other
    
    func dealCyclePageIndex(state: YDCanCycleScrollView.CycleScrollState)  {
        
        if state == .leftBoundary || state == .rightBoundary{
            
            
            if state == .leftBoundary {
                currentModel.cyclePageIndex.value = preCyclePageIndex()
            }else{
                currentModel.cyclePageIndex.value = nextCyclePageIndex()
            }
            
            reAddContentView()
            
            self.scrollView.setContentOffset(CGPoint.init(x: self.frame.width, y: 0), animated: false)
            
        }
        
    }
    
    func getCyclePageIndexView() -> UIView {
        let x =  safe_getContentViews(index: currentModel.cyclePageIndex.value)
        x.frame = self.bounds
        return x
    }
    
    func preCyclePageView() -> UIView {
        let x =  safe_getContentViews(index: preCyclePageIndex())
        x.frame = self.bounds
        return x
    }
    
    func nextCyclePageView() -> UIView {
        let x =  safe_getContentViews(index: nextCyclePageIndex())
        x.frame = self.bounds
        return x
    }
    
    func preCyclePageIndex() -> Int {
        var index = currentModel.cyclePageIndex.value
        index -= 1
        if index < 0 {
            index = currentModel.yd_contentViews.count - 1
        }
        return index
    }
    
    func nextCyclePageIndex() -> Int{
        
        var index = currentModel.cyclePageIndex.value
        index += 1
        if index == currentModel.yd_contentViews.count {
            index = 0
        }
        return index
    }
    
    func reAddContentView() {
        
        let _ = views.flatMap{  $0.subviews }
            .map({ (x: UIView)  in
                x.removeFromSuperview()
            })
        
        
        
        var content = getCyclePageIndexView()
        centerView.addSubview(content)
        content.snp.makeConstraints { (ConstraintMaker) in
            ConstraintMaker.edges.equalTo(UIEdgeInsets.zero)
        }
        
        self.scrollView.isScrollEnabled = currentModel.viewCount > 1
        //特殊处理
        if currentModel.viewCount == 1 {
            return
        }
        
        content = preCyclePageView()
        leftView.addSubview(content)
        content.snp.makeConstraints { (ConstraintMaker) in
            ConstraintMaker.edges.equalTo(UIEdgeInsets.zero)
        }
        
        content = nextCyclePageView()
        rightView.addSubview(content)
        content.snp.makeConstraints { (ConstraintMaker) in
            ConstraintMaker.edges.equalTo(UIEdgeInsets.zero)
        }
    }
    
    func safe_getContentViews(index: Int) -> UIView {
        
        if index < currentModel.yd_contentViews.count && index  >= 0 {
            
            return currentModel.yd_contentViews[index]
            
        } else {
            
            printLog("error: getContentViews failed")
            return UIView()
            
        }
        
    }
}

public class YDCanCycleScrollViewModel: YDCycleScrollViewModel {
    
    public typealias ContentViewsBlock = (Int) -> UIView
    
    public var viewCount: Int
    
    private var getContentviewsBlock: ContentViewsBlock
    
    var refreshBlock: (() -> Void)?
    
    public init(parentViewModel: MVVM_BaseViewModel?, getContentviewsBlock: @escaping ContentViewsBlock, viewCount: Int) {
        self.viewCount = viewCount
        self.getContentviewsBlock = getContentviewsBlock
        super.init(parentViewModel: parentViewModel, startIndex: 0, canCycle: true)
        
        createContentViews()
    }
    
    public func refresh(viewCount: Int) {
        self.viewCount = viewCount
        self.cyclePageIndex.value = 0
        createContentViews()
        
        refreshBlock?()
    }
    
    func createContentViews() {
        
        self.yd_contentViews.removeAll()
        
        for index in 0..<viewCount {
            yd_contentViews.append(getContentviewsBlock(index))
        }
        
        if viewCount == 1 {
            /*
             * 一个不让滑动
             yd_contentViews.append(getContentviewsBlock(0))
             yd_contentViews.append(getContentviewsBlock(0))
             */
        } else if viewCount == 2 {
            for index in 0..<viewCount {
                yd_contentViews.append(getContentviewsBlock(index))
            }
        }
    }
    
}

